package ar.edu.itba.pod.legajo47573;

import java.rmi.AlreadyBoundException;
import java.rmi.RemoteException;
import java.rmi.server.UnicastRemoteObject;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.CountDownLatch;

import ar.edu.itba.balance.api.AgentsTransfer;
import ar.edu.itba.balance.api.NodeAgent;
import ar.edu.itba.event.EventInformation;
import ar.edu.itba.event.RemoteEventDispatcher;
import ar.edu.itba.node.Node;
import ar.edu.itba.pod.agent.runner.Agent;
import ar.edu.itba.pod.agent.runner.Simulation;

@SuppressWarnings("serial")
public class AgentsTransferImpl extends UnicastRemoteObject implements AgentsTransfer{

	private MyNode currentNode;
	//private CountDownLatch transferLatch = null;

	public AgentsTransferImpl(MyNode currentNode) throws RemoteException{
		super();
		this.currentNode = currentNode;
		try {
			currentNode.getRegistry().bind(Node.AGENTS_TRANSFER, this);
		} catch (AlreadyBoundException e) {
			e.printStackTrace();
		}
	}

	@Override
	public void runAgentsOnNode(List<NodeAgent> agents) throws RemoteException {
//		if(transferLatch != null){
//		try {
//			transferLatch.await();
//		} catch (InterruptedException e1) {
//			// TODO Auto-generated catch block
//			e1.printStackTrace();
//		}
//		}
//		synchronized(AgentsTransfer.class){
		Simulation simulation = currentNode.getSimulation();
		System.out.println("Lista de agentes en runAgentsOnNode " + agents.size());
		RemoteEventDispatcher stub = (RemoteEventDispatcher)Registries.getRemoteObject(currentNode, agents.get(0).node(), Node.DISTRIBUTED_EVENT_DISPATCHER);

		
		/*Sincronizacion de eventos*/
		Set<EventInformation> newEventsForHim = currentNode.getRemoteDispatcher().newEventsFor(agents.get(0).node());
		for(EventInformation it : newEventsForHim){
			try {
				stub.publish(it);
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
		
		/*Pido los eventos del otro nodo que son para mi*/
		Set<EventInformation> newEventsForMe = stub.newEventsFor(currentNode.getInfo());
		for(EventInformation it : newEventsForMe){
			try {
				currentNode.getRemoteDispatcher().publish(it);
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
		
		for(NodeAgent it : agents){
			BlockingQueue<Object> queue = stub.moveQueueFor(it.agent());
			((EventDispatcherImpl)currentNode.getDispatcher()).setAgentQueue(it.agent(), queue);
			((MyLocalSimulation)simulation).addAgentRemote(it.agent());
		}
//		}
	}

	@Override
	public int getNumberOfAgents() throws RemoteException {
		return currentNode.getSimulation().agentsRunning();
	}

	@Override
	public List<NodeAgent> stopAndGet(int numberOfAgents) throws RemoteException {
//		transferLatch = new CountDownLatch(1);
		Simulation sim = currentNode.getSimulation();
		List<Agent> agents = sim.getAgentsRunning();
		List<Agent> agentsToStop = agents.subList(0, numberOfAgents);
		List<NodeAgent> ans = new ArrayList<NodeAgent>();

		for(Agent it : agentsToStop){
			ans.add(new NodeAgent(currentNode.getInfo(), it));
			sim.remove(it);
		}

//		transferLatch.countDown();
		return ans;
	}
}
